package com.fary.beans.factory.support;

import com.fary.core.SpringException;
import com.fary.core.env.Environment;
import com.fary.core.env.EnvironmentCapable;
import com.fary.core.env.StandardEnvironment;
import com.fary.core.io.Resource;
import com.fary.core.io.ResourceLoader;
import com.fary.core.io.support.PathMatchingResourcePatternResolver;
import com.fary.core.io.support.ResourcePatternResolver;
import com.fary.util.Assert;


import java.io.IOException;
import java.util.Collections;
import java.util.Set;

public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader, EnvironmentCapable {

    private final BeanDefinitionRegistry registry;

    private ResourceLoader resourceLoader;

    private ClassLoader beanClassLoader;

    private Environment environment;

    private BeanNameGenerator beanNameGenerator = new DefaultBeanNameGenerator();

    protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        this.registry = registry;

        // Determine ResourceLoader to use.
        if (this.registry instanceof ResourceLoader) {
            this.resourceLoader = (ResourceLoader) this.registry;
        } else {
            this.resourceLoader = new PathMatchingResourcePatternResolver();
        }

        // Inherit Environment if possible
        if (this.registry instanceof EnvironmentCapable) {
            this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
        } else {
            this.environment = new StandardEnvironment();
        }
    }


    @Override
    public final BeanDefinitionRegistry getRegistry() {
        return this.registry;
    }

    @Override
    public BeanNameGenerator getBeanNameGenerator() {
        return this.beanNameGenerator;
    }

    /**
     * 获取bean类加载器
     */
    @Override
    public ClassLoader getBeanClassLoader() {
        return this.beanClassLoader;
    }

    /**
     * 获取资源加载器
     */
    @Override
    public ResourceLoader getResourceLoader() {
        return this.resourceLoader;
    }

    /**
     * 设置资源加载器
     */
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }


    /**
     * 获取环境变量
     */
    @Override
    public Environment getEnvironment() {
        return this.environment;
    }

    /**
     * 设置环境
     * @param environment
     */
    public void setEnvironment(Environment environment) {
        Assert.notNull(environment, "Environment must not be null");
        this.environment = environment;
    }

    /**
     * 根据地址加载资源文件
     */
    public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws SpringException {
        ResourceLoader resourceLoader = getResourceLoader();
        if (resourceLoader == null) {
            throw new SpringException("Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
        }

        if (resourceLoader instanceof ResourcePatternResolver) {
            // Resource pattern matching available.
            try {
                Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
                int count = loadBeanDefinitions(resources);
                if (actualResources != null) {
                    Collections.addAll(actualResources, resources);
                }
                return count;
            } catch (IOException ex) {
                throw new SpringException("Could not resolve bean definition resource pattern [" + location + "]", ex);
            }
        } else {
            // Can only load single resources by absolute URL.
            Resource resource = resourceLoader.getResource(location);
            int count = loadBeanDefinitions(resource);
            if (actualResources != null) {
                actualResources.add(resource);
            }
            return count;
        }
    }

    /**
     * 加载多个资源文件
     */
    @Override
    public int loadBeanDefinitions(Resource... resources) throws SpringException {
        Assert.notNull(resources, "Resource array must not be null");
        int count = 0;
        for (Resource resource : resources) {
            count += loadBeanDefinitions(resource);
        }
        return count;
    }

}